﻿using System.Runtime.Intrinsics;
using System.Runtime.Intrinsics.X86;

namespace SimdTest2.Methods
{
    [Algorithm(true, AlgorithmType.Three)]
    public unsafe class ThreeMethod : AlgorithmBase
    {
        public ThreeMethod(int row, int col) : base(row, col)
        {
        }
        Point[] _data;
        protected override void CreateData()
        {
            _data = new Point[_size];
            Random random = new Random();
            for (int i = 0; i < _size; i++)
            {
                _data[i] = new Point(random.Next(999), random.Next(999));
            }
        }
        protected override void OrdinaryMethod()
        {
            List<int> list = new List<int>();
            for (int i = 0; i < _size; i++)
            {
                for (int j = 0; j < _size; j++)
                {
                    var dif = Math.Abs(_data[i].X - _data[j].X) + Math.Abs(_data[i].Y - _data[j].Y);
                    list.Add(dif);
                }
            }
        }

        protected override void SimdMethod()
        {
            int n = _data.Length;
            int m = (n * n - n) >> 1;
            int vsize = Vector128<int>.Count;
            if (n <= vsize)
            {
                int[] ints = new int[m];
                int k = 0;
                fixed (Point* ptr = _data)
                {
                    for (int i = 0; i < n; i++)
                    {
                        Point* p1 = ptr + i;
                        for (int j = i + 1; j < n; j++)
                        {
                            Point* p2 = ptr + j;
                            int dif = Math.Abs(p1->X - p2->X) + Math.Abs(p1->Y - p2->Y);
                            ints[k++] = dif;
                        }
                    }
                }
            }
            int t = 0;
            int[] xs = new int[n];
            int[] ys = new int[n];
            List<Vector128<int>> vectors = new List<Vector128<int>>(m);
            fixed (Point* ptr = _data)
            {
                fixed (int* xptr = xs, yptr = ys)
                {
                    for (int i = 0; i < n; i++)
                    {
                        Point* p = ptr + i;
                        *(xptr + i) = p->X;
                        *(yptr + i) += p->Y;
                    }
                    for (int i = 0; i < n; i += vsize)
                    {
                        Vector128<int> vx1 = *(Vector128<int>*)(xptr + i);
                        Vector128<int> vy1 = *(Vector128<int>*)(yptr + i);
                        for (int j = i + 1; j < n; j++)
                        {
                            Vector128<int> vx2 = *(Vector128<int>*)(xptr + j);
                            Vector128<int> vy2 = *(Vector128<int>*)(yptr + j);
                            var vDifference = Sse2.Add(Vector128.Abs(Sse2.Subtract(vx1, vx2)), Vector128.Abs(Sse2.Subtract(vy1, vy2)));
                            vectors.Add(vDifference);
                        }
                    }
                }
            }
        }
    }
}
